﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

using System.Text;

namespace System.Data.SugarClient
{

	public class SugarDataReader : DbDataReader
	{

		#region Constructors

		internal SugarDataReader(
			IGetEntryListActionResult soapResult)
		{
			this._soapActionResult = soapResult;
		}

		#endregion

		#region Fields

		private IGetEntryListActionResult _soapActionResult;
		private int _cursor = -1;
		private bool _isClosed = false;

		#endregion

		#region Properties

		internal IGetEntryListActionResult SoapActionResult
		{
			get { return _soapActionResult; }
		}

		#endregion

		public override void Close()
		{
			_isClosed = true;
		}

		public override bool Read()
		{
			++_cursor;
			this.PerformPagingIfNeeded();
			return (_cursor < this._soapActionResult.Count);
		}

		private void PerformPagingIfNeeded()
		{
			if (this._soapActionResult.Count <= _cursor) NextPage();
		}

		private void NextPage()
		{
			ISugarSoapAction action = this._soapActionResult.NextPageAction();
			if (action != null)
			{
				this._soapActionResult = action.Execute() as IGetEntryListActionResult;
			}
			this._cursor = 0;
		}

		private object DBNull(object value)
		{
			return (value == null) ? System.DBNull.Value : value;
		}
		public override object this[string name]
		{
			get { return this[this.SoapActionResult.IndexOf(name)]; }
		}

		public override object this[int ordinal]
		{
			get { return DBNull(this.SoapActionResult[this._cursor, ordinal]); }
		}

		public override bool IsClosed
		{
			get { return this._isClosed; }
		}

		public override int FieldCount
		{
			get { return this.SoapActionResult.FieldCount; }
		}

		public override string GetName(int ordinal)
		{
			return this.SoapActionResult.GetFieldNameAt(ordinal);
		}

		public override bool NextResult()
		{
			return false;
		}

		public override Type GetFieldType(int ordinal)
		{
			return typeof(string);
		}

		public override int GetValues(object[] values)
		{
			int i;
			for (i = 0; i < this.FieldCount; ++i) { values[i] = this[i]; }
			return i;
		}

		public override int Depth
		{
			get { throw new NotImplementedException(); }
		}

		public override bool GetBoolean(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override byte GetByte(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length)
		{
			throw new NotImplementedException();
		}

		public override char GetChar(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length)
		{
			throw new NotImplementedException();
		}

		public override string GetDataTypeName(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override DateTime GetDateTime(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override decimal GetDecimal(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override double GetDouble(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override System.Collections.IEnumerator GetEnumerator()
		{
			throw new NotImplementedException();
		}

		public override float GetFloat(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override Guid GetGuid(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override short GetInt16(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override int GetInt32(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override long GetInt64(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override int GetOrdinal(string name)
		{
			throw new NotImplementedException();
		}

		public override DataTable GetSchemaTable()
		{
			DataTable table = new DataTable();

			/*
			 * http://msdn.microsoft.com/ja-jp/library/system.data.datatablereader.getschematable.aspx
				ColumnName					列が DataTable に表示されるときの名前。	
				ColumnOrdinal				列の序数。	
				ColumnSize					DataColumn の ColumnSize (または MaxLength) プロパティが確認できない、または無関係な場合は -1。それ以外の場合は 0 または MaxLength 値を格納する正の整数値。	
				NumericPrecision		列の型が数値型の場合は、列の最大精度になります。列の型が数値データ型ではない場合は null 値です。	
				NumericScale				列のデータ型に小数点以下の部分がある場合、小数点の右側の桁数を返します。それ以外の場合は、null 値を返します。	
				DataType						基になる列の型。	
				ProviderType				列のデータ型のインジケータ。行によって列のデータ型が異なる場合、この値は Object になります。この列に null 値を含めることはできません。	
				IsLong							列のデータ型が String で、列の MaxLength プロパティが -1 の場合は、true。それ以外の場合は false。	
				AllowDBNull					列の AllowDbNull 制約が true に設定されている場合は、true。それ以外の場合は false。	
				IsReadOnly					列を変更できない場合は true。それ以外の場合は false。	
				IsRowVersion				すべての列で false。	
				IsUnique						true の場合は、この列で同じ値を持つ 2 つの行は DataTable 内に存在しません。列自体がキーを表す場合、またはこの列にのみ適用される UNIQUE 型の制約がある場合、IsUnique は常に true になります。false の場合は、列には DataTable 内で重複している値を格納できます。この列の既定値は false です。	
				IsKey								true の場合は、列が DataTable の行を一意に識別するために組み合わされる、列のセットの 1 つであることを示します。IsKey が true に設定された列のセットは、DataTable 内の行を一意に識別する必要があります。この列のセットが列の最小セットである必要はありません。この列のセットは、DataTable の主キー、UNIQUE 制約、または一意のインデックスから生成されることもあります。false の場合は、列が、行を一意に識別する必要がないことを示します。列が単一の主キーまたは複合主キーに関与している場合、この値は true になります。それ以外の場合、値は false になります。	
				IsAutoIncrement			true の場合は、列が、新しい行に固定インクリメントで値を割り当てることを示します。false の場合は、列が、新しい行に固定インクリメントで値を割り当てないことを示します。この列の既定値は false です。	
				BaseCatalogName			この列を格納するデータ ストア内のカタログの名前。ベース カタログ名を確認できない場合は Null。この列の既定値は nullNothingnullptrnull 参照 (Visual Basic では Nothing) 値です。	
				BaseSchemaName			この値は常に Null です。	
				BaseTableName				DataTable の名前。	
				BaseColumnName			DataTable 内の列名。	
				AutoIncrementSeed		DataTable の AutoIncrementSeed プロパティの値。	
				AutoIncrementStep		DataTable の AutoIncrementStep プロパティの値。	
				DefaultValue				DataColumn の DefaultValue プロパティの値。	
				Expression					現在の列が式列であり、式で使用されているすべての列が、その式列を格納している T:System.Data.DataTable に属している場合、これは式の文字列になります。それ以外の場合は nullNothingnullptrnull 参照 (Visual Basic では Nothing)。	
				ColumnMapping				DataColumn に関連付けられた MappingType 値。Attribute、Element、Hidden、SimpleContent のいずれかの値になります。既定値は Element です。	
				BaseTableNamespace	DataTable の Namespace プロパティの値。	
				BaseColumnNamespace	DataColumn の Namespace プロパティの値。
			 */

			table.Columns.Add("ColumnName", typeof(string));
			table.Columns.Add("ColumnOrdinal", typeof(int));
			table.Columns.Add("DataType", typeof(Type));
			table.Columns.Add("AllowDBNull", typeof(bool));
			table.Columns.Add("IsReadOnly", typeof(bool));
			table.Columns.Add("IsKey", typeof(bool));
			table.Columns.Add("IsUnique", typeof(bool));
			table.Columns.Add("BaseTableName", typeof(string));
			table.Columns.Add("BaseColumnName", typeof(string));
			table.Columns.Add("DefaultValue", typeof(string));

			for (int i = 0; i < this.SoapActionResult.FieldCount; ++i)
			{
				SugarVarDef vardef = this.SoapActionResult.GetVarDefAt(i);
				DataRow row = table.NewRow();
				row["ColumnName"] = vardef.Name;
				row["ColumnOrdinal"] = i;
				row["DataType"] = vardef.DataType;
				row["AllowDBNull"] = !vardef.Required;
				row["IsReadOnly"] = vardef.Name.ToUpper().Equals("ID");
				row["IsKey"] = vardef.Name.ToUpper().Equals("ID");
				row["IsUnique"] = vardef.Name.ToUpper().Equals("ID");
				row["BaseTableName"] = this.SoapActionResult.Action.Module;
				row["BaseColumnName"] = vardef.Name;
				row["DefaultValue"] = vardef.DefaultValue;
				table.Rows.Add(row);

				if (vardef.Required)
				{
					Trace.Debug("\"{0}\" is Required.", vardef.Name);
				}
			}
			return table;
		}

		public override string GetString(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override object GetValue(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override bool HasRows
		{
			get { throw new NotImplementedException(); }
		}

		public override bool IsDBNull(int ordinal)
		{
			throw new NotImplementedException();
		}

		public override int RecordsAffected
		{
			get { throw new NotImplementedException(); }
		}

		
	}
}
